#include "ServerComm.h"
#include "Command.h"
#include "Controller.h"

ServerComm::ServerComm()
{
	NonBlocking = true;
    ListenSocket = INVALID_SOCKET;
	for(int i=0;i<NUM_MAX_CLIENTS;++i)
		ClientSocket[i] = INVALID_SOCKET;
	numClients = 0;

    result = NULL;
    hints;

    recvbuflen = DEFAULT_BUFLEN;
    
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if(iResult != 0) {	printf("WSAStartup failed with error: %d\n", iResult);	return;}

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    // Resolve the server address and port
    iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
    if( iResult != 0 ) {	printf("getaddrinfo failed with error: %d\n", iResult);	WSACleanup();	return;}

    // Create a SOCKET for connecting to server
    ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if(ListenSocket == INVALID_SOCKET) {	printf("socket failed with error: %ld\n", WSAGetLastError());	freeaddrinfo(result);	WSACleanup();	return;}

	//Make non-Blocking
	iResult = ioctlsocket(ListenSocket, FIONBIO, &NonBlocking);
	if (iResult != NO_ERROR)	printf("ioctlsocket failed with error: %ld\n", iResult);


    // Setup the TCP listening socket
    iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
    if(iResult == SOCKET_ERROR) {	printf("bind failed with error: %d\n", WSAGetLastError());	freeaddrinfo(result);	closesocket(ListenSocket);	WSACleanup();	return;}

    freeaddrinfo(result);

    iResult = listen(ListenSocket, SOMAXCONN);
    if (iResult == SOCKET_ERROR) {	printf("listen failed with error: %d\n", WSAGetLastError());	closesocket(ListenSocket);	WSACleanup();	return;}
}

ServerComm::~ServerComm()
{
    closesocket(ListenSocket);
    WSACleanup();
}

void ServerComm::Init(Controller* c)
{
	control = c;
}

void ServerComm::RunCommCheck(Command* Cmd)
{
	if(numClients < NUM_MAX_CLIENTS)
		CheckForNewClient();
	for(int i=0;i<numClients;++i)
	{
		CurrentClient = i;
		if(CheckForData())
			ProcessData(Cmd);
	}
}

void ServerComm::CheckForNewClient()
{
	ClientSocket[numClients] = accept(ListenSocket, NULL, NULL);
	if(ClientSocket[numClients] != INVALID_SOCKET)
	{
		numClients++;
		printf("Clients connected: %d\n", numClients);
	}
}

bool ServerComm::CheckForData()
{
	iResult = recv(ClientSocket[CurrentClient], recvbuf, recvbuflen, 0);
	if (iResult > 0)
		return true;
	return false;
}

void ServerComm::ProcessData(Command* Cmd)
{
	//decode message
	Cmd->unPack(recvbuf);
	//add game number
	Cmd->setGameNumber(CurrentClient);
	//send to gameState
	control->Send();
	//encode result
	Cmd->Pack(recvbuf);
	//send back to client
	iSendResult = send( ClientSocket[CurrentClient], recvbuf, iResult, 0 );
	if (iSendResult == SOCKET_ERROR) {	printf("send failed with error: %d\n", WSAGetLastError());	closesocket(ClientSocket[CurrentClient]);	WSACleanup();	return;}
}